package com.azier.influxdb.mapper;

import com.azier.influxdb.util.InfluxDBConnectionUtil;
import com.azier.influxdb.util.InfluxDBHandleUtil;
import org.influxdb.InfluxDB;
import org.influxdb.InfluxDBMapperException;
import org.influxdb.annotation.Column;
import org.influxdb.annotation.Measurement;
import org.influxdb.dto.Point;
import org.influxdb.dto.Query;
import org.influxdb.dto.QueryResult;
import org.influxdb.impl.InfluxDBMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.lang.reflect.Field;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.TimeUnit;

import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.op;
import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.select;

public class InfluxDBBaseMapper extends InfluxDBMapper{

    @Value("${influxDB.database:seem}")
    private String              publicDatabase;

    @Autowired
    InfluxDBConnectionUtil influxDBConnectionUtil;

    private InfluxDB influxDB;

    public InfluxDBBaseMapper(InfluxDB influxDB) {
        super(influxDB);
        this.influxDB = influxDB;
    }

    public List<List<Map<String,Object>>> countAll(String database,String table){
        Query select = select().countAll().from(database, table);
        QueryResult results = influxDB.query(select);
        return InfluxDBHandleUtil.analysisResult(results);
    }

    public QueryResult query(Query select){
        return influxDB.query(select);
    }

    public <T> List<T> myQuery(Query query,Class clazz){
        this.throwExceptionIfMissingAnnotation(clazz);
        long s = System.currentTimeMillis();
        QueryResult queryResult = this.influxDB.query(query);
        long s1 = System.currentTimeMillis();
        System.out.println(s1-s);
        String measurementName = InfluxDBHandleUtil.getMeasurementName(clazz);
        List<T> l = this.toPOJOByMyColumn(queryResult, clazz, measurementName, TimeUnit.MILLISECONDS);
        long e = System.currentTimeMillis();
        System.out.println(e-s1);
        return l;
    }

    public <T> Map<T,List<T>> myQueryGroupBySeries(Query query,Class clazz){
        this.throwExceptionIfMissingAnnotation(clazz);
        QueryResult queryResult = this.influxDB.query(query);
        String measurementName = InfluxDBHandleUtil.getMeasurementName(clazz);
        return this.toPOJOByMyColumnAndSeries(queryResult, clazz, measurementName, TimeUnit.MILLISECONDS);
    }
    public <T> Map<T,List<T>> toPOJOBySeries(QueryResult queryResult, Class<T> clazz, String measurementName, TimeUnit precision) throws InfluxDBMapperException {
        Objects.requireNonNull(measurementName, "measurementName");
        Objects.requireNonNull(queryResult, "queryResult");
        Objects.requireNonNull(clazz, "clazz");
        this.throwExceptionIfResultWithError(queryResult);
        Map<T,List<T>> result = new ConcurrentHashMap<>();
        queryResult.getResults().stream().filter((internalResult) -> {
            return Objects.nonNull(internalResult) && Objects.nonNull(internalResult.getSeries());
        }).forEach((internalResult) -> {
            internalResult.getSeries().stream().filter((series) -> {
                return series.getName().equals(measurementName);
            }).forEachOrdered((series) -> {
                this.parseSeriesAs(series, clazz, result, precision);
            });
        });
        return result;
    }
    void throwExceptionIfMissingAnnotation(Class<?> clazz) {
        if (!clazz.isAnnotationPresent(Measurement.class)) {
            throw new IllegalArgumentException("Class " + clazz.getName() + " is not annotated with @" + Measurement.class.getSimpleName());
        }
    }
    void throwExceptionIfResultWithError(QueryResult queryResult) {
        if (queryResult.getError() != null) {
            throw new InfluxDBMapperException("InfluxDB returned an error: " + queryResult.getError());
        } else {
            queryResult.getResults().forEach((seriesResult) -> {
                if (seriesResult.getError() != null) {
                    throw new InfluxDBMapperException("InfluxDB returned an error with Series: " + seriesResult.getError());
                }
            });
        }
    }
    <T> Map<T,List<T>> parseSeriesAs(QueryResult.Series series, Class<T> clazz,Map<T,List<T>> result, TimeUnit precision) {
        int columnSize = series.getColumns().size();
        ConcurrentMap colNameAndFieldMap = InfluxDBHandleUtil.getColumn(clazz);
        List<T> list = new LinkedList<>();
        try {
            T object = null;
            Iterator var8 = series.getValues().iterator();

            //记录并设定tag
            int flag = 0;
            T seriesObject = clazz.newInstance();
            while(var8.hasNext()) {
                List<Object> row = (List)var8.next();

                for(int i = 0; i < columnSize; ++i) {
                    Field correspondingField = (Field)colNameAndFieldMap.get(series.getColumns().get(i));
                    if (correspondingField != null) {
                        if (object == null) {
                            object = clazz.newInstance();
                        }
                        this.setFieldValue(object, correspondingField, row.get(i), precision);
                    }
                }

                if (series.getTags() != null && !series.getTags().isEmpty()) {
                    Iterator var14 = series.getTags().entrySet().iterator();

                    while(var14.hasNext()) {
                        Map.Entry<String, String> entry = (Map.Entry)var14.next();
                        Field correspondingField = (Field)colNameAndFieldMap.get(entry.getKey());
                        if (correspondingField != null) {
                            this.setFieldValue(object, correspondingField, entry.getValue(), precision);
                            if(flag==0){
                                this.setFieldValue(seriesObject, correspondingField, entry.getValue(), precision);
                            }
                        }
                    }
                }

                if (object != null) {
                    list.add(object);
                    object = null;
                }
                flag++;
            }
            result.put(seriesObject,list);
            return result;
        } catch (IllegalAccessException | InstantiationException var13) {
            throw new InfluxDBMapperException(var13);
        }
    }

    <T> void setFieldValue(T object, Field field, Object value, TimeUnit precision) throws IllegalArgumentException, IllegalAccessException {
        if (value != null) {
            Class fieldType = field.getType();

            try {
                if (!field.isAccessible()) {
                    field.setAccessible(true);
                }

                if (!this.fieldValueModified(fieldType, field, object, value, precision) && !this.fieldValueForPrimitivesModified(fieldType, field, object, value) && !this.fieldValueForPrimitiveWrappersModified(fieldType, field, object, value)) {
                    String msg = "Class '%s' field '%s' is from an unsupported type '%s'.";
                    throw new InfluxDBMapperException(String.format(msg, object.getClass().getName(), field.getName(), field.getType()));
                }
            } catch (ClassCastException var8) {
                String msg = "Class '%s' field '%s' was defined with a different field type and caused a ClassCastException. The correct type is '%s' (current field value: '%s').";
                throw new InfluxDBMapperException(String.format(msg, object.getClass().getName(), field.getName(), value.getClass().getName(), value));
            }
        }
    }

    /**
     * 将符合clounm注解的数据赋值到字段中
     * 将符合myclounm注解的数据赋值到字段中
     * 不区分时间线
     * @param clazz
     * @param precision
     * @param <T>
     * @return
     */
    public <T> List<T> toPOJOByMyColumn(QueryResult queryResult, Class<T> clazz, String measurementName, TimeUnit precision) throws InfluxDBMapperException {
        Objects.requireNonNull(measurementName, "measurementName");
        Objects.requireNonNull(queryResult, "queryResult");
        Objects.requireNonNull(clazz, "clazz");
        this.throwExceptionIfResultWithError(queryResult);
        List<T> result = new LinkedList<>();
        queryResult.getResults().stream().filter((internalResult) -> {
            return Objects.nonNull(internalResult) && Objects.nonNull(internalResult.getSeries());
        }).forEach((internalResult) -> {
            internalResult.getSeries().stream().filter((series) -> {
                return series.getName().equals(measurementName);
            }).forEachOrdered((series) -> {
                this.myPares(series, clazz, result, precision);
            });
        });
        return result;
    }
    <T> List<T> myPares(QueryResult.Series series, Class<T> clazz,List<T> result, TimeUnit precision) {
        int columnSize = series.getColumns().size();
        ConcurrentMap colNameAndFieldMap = InfluxDBHandleUtil.getColumn(clazz);
        ConcurrentMap myColumnAnnotation = InfluxDBHandleUtil.getMyColumnAnnotation(clazz);

        try {
            T object = null;
            Iterator var8 = series.getValues().iterator();

            //记录并设定tag
            int flag = 0;
            T seriesObject = clazz.newInstance();
            while(var8.hasNext()) {
                List<Object> row = (List)var8.next();

                for(int i = 0; i < columnSize; ++i) {
                    Field correspondingField = (Field)colNameAndFieldMap.get(series.getColumns().get(i));

                    if (correspondingField != null) {
                        if (object == null) {
                            object = clazz.newInstance();
                        }

                        this.setFieldValue(object, correspondingField, row.get(i), precision);
                    }else {
                        Field myColumn = (Field)myColumnAnnotation.get(series.getColumns().get(i));
                        if (myColumn != null) {
                            if (object == null) {
                                object = clazz.newInstance();
                            }
                            this.setFieldValue(object, myColumn, row.get(i), precision);
                        }
                    }
                }

                if (series.getTags() != null && !series.getTags().isEmpty()) {
                    Iterator var14 = series.getTags().entrySet().iterator();

                    while(var14.hasNext()) {
                        Map.Entry<String, String> entry = (Map.Entry)var14.next();
                        Field correspondingField = (Field)colNameAndFieldMap.get(entry.getKey());
                        if (correspondingField != null) {
                            this.setFieldValue(object, correspondingField, entry.getValue(), precision);
                            if(flag==0){
                                this.setFieldValue(seriesObject, correspondingField, entry.getValue(), precision);
                            }
                        }
                    }
                }

                if (object != null) {
                    result.add(object);
                    object = null;
                }
                flag++;
            }
            return result;
        } catch (IllegalAccessException | InstantiationException var13) {
            throw new InfluxDBMapperException(var13);
        }
    }
    /**
     * 将符合clounm注解的数据赋值到字段中
     * 将符合myclounm注解的数据赋值到字段中
     * 区分时间线
     * @param clazz
     * @param precision
     * @param <T>
     * @return
     */
    public <T> Map<T,List<T>> toPOJOByMyColumnAndSeries(QueryResult queryResult, Class<T> clazz, String measurementName, TimeUnit precision) throws InfluxDBMapperException {
        Objects.requireNonNull(measurementName, "measurementName");
        Objects.requireNonNull(queryResult, "queryResult");
        Objects.requireNonNull(clazz, "clazz");
        this.throwExceptionIfResultWithError(queryResult);
        Map<T,List<T>> result = new ConcurrentHashMap<>();
        queryResult.getResults().stream().filter((internalResult) -> {
            return Objects.nonNull(internalResult) && Objects.nonNull(internalResult.getSeries());
        }).forEach((internalResult) -> {
            internalResult.getSeries().stream().filter((series) -> {
                return series.getName().equals(measurementName);
            }).forEachOrdered((series) -> {
                this.myParesAndSeries(series, clazz, result, precision);
            });
        });
        return result;
    }
    <T> Map<T,List<T>> myParesAndSeries(QueryResult.Series series, Class<T> clazz,Map<T,List<T>> result, TimeUnit precision) {
        int columnSize = series.getColumns().size();
        ConcurrentMap colNameAndFieldMap = InfluxDBHandleUtil.getColumn(clazz);
        ConcurrentMap myColumnAnnotation = InfluxDBHandleUtil.getMyColumnAnnotation(clazz);
        List<T> list = new LinkedList<>();
        try {
            T object = null;
            Iterator var8 = series.getValues().iterator();

            //记录并设定tag
            int flag = 0;
            T seriesObject = clazz.newInstance();
            while(var8.hasNext()) {
                List<Object> row = (List)var8.next();

                for(int i = 0; i < columnSize; ++i) {
                    Field correspondingField = (Field)colNameAndFieldMap.get(series.getColumns().get(i));

                    if (correspondingField != null) {
                        if (object == null) {
                            object = clazz.newInstance();
                        }

                        this.setFieldValue(object, correspondingField, row.get(i), precision);
                    }else {
                        Field myColumn = (Field)myColumnAnnotation.get(series.getColumns().get(i));
                        if (myColumn != null) {
                            if (object == null) {
                                object = clazz.newInstance();
                            }
                            this.setFieldValue(object, myColumn, row.get(i), precision);
                        }
                    }
                }

                if (series.getTags() != null && !series.getTags().isEmpty()) {
                    Iterator var14 = series.getTags().entrySet().iterator();

                    while(var14.hasNext()) {
                        Map.Entry<String, String> entry = (Map.Entry)var14.next();
                        Field correspondingField = (Field)colNameAndFieldMap.get(entry.getKey());
                        if (correspondingField != null) {
                            this.setFieldValue(object, correspondingField, entry.getValue(), precision);
                            if(flag==0){
                                this.setFieldValue(seriesObject, correspondingField, entry.getValue(), precision);
                            }
                        }
                    }
                }

                if (object != null) {
                    list.add(object);
                    object = null;
                }

                flag++;

            }
            result.put(seriesObject,list);
            return result;
        } catch (IllegalAccessException | InstantiationException var13) {
            throw new InfluxDBMapperException(var13);
        }
    }
    <T> boolean fieldValueModified(Class<?> fieldType, Field field, T object, Object value, TimeUnit precision) throws IllegalArgumentException, IllegalAccessException {
        DateTimeFormatter RFC3339_FORMATTER = (new DateTimeFormatterBuilder()).appendPattern("yyyy-MM-dd'T'HH:mm:ss").appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true).appendZoneOrOffsetId().toFormatter();
        if (String.class.isAssignableFrom(fieldType)) {
            field.set(object, String.valueOf(value));
            return true;
        } else if (Instant.class.isAssignableFrom(fieldType)) {
            Instant instant;
            if (value instanceof String) {
                instant = Instant.from(RFC3339_FORMATTER.parse(String.valueOf(value)));
            } else if (value instanceof Long) {
                instant = Instant.ofEpochMilli(this.toMillis((Long)value, precision));
            } else if (value instanceof Double) {
                instant = Instant.ofEpochMilli(this.toMillis(((Double)value).longValue(), precision));
            } else {
                if (!(value instanceof Integer)) {
                    throw new InfluxDBMapperException("Unsupported type " + field.getClass() + " for field " + field.getName());
                }

                instant = Instant.ofEpochMilli(this.toMillis(((Integer)value).longValue(), precision));
            }

            field.set(object, instant);
            return true;
        } else {
            return false;
        }
    }
    private Long toMillis(long value, TimeUnit precision) {
        return TimeUnit.MILLISECONDS.convert(value, precision);
    }

    <T> boolean fieldValueForPrimitivesModified(Class<?> fieldType, Field field, T object, Object value) throws IllegalArgumentException, IllegalAccessException {
        if (Double.TYPE.isAssignableFrom(fieldType)) {
            field.setDouble(object, (Double)value);
            return true;
        } else if (Long.TYPE.isAssignableFrom(fieldType)) {
            field.setLong(object, ((Double)value).longValue());
            return true;
        } else if (Integer.TYPE.isAssignableFrom(fieldType)) {
            field.setInt(object, ((Double)value).intValue());
            return true;
        } else if (Boolean.TYPE.isAssignableFrom(fieldType)) {
            field.setBoolean(object, Boolean.valueOf(String.valueOf(value)));
            return true;
        } else {
            return false;
        }
    }

    <T> boolean fieldValueForPrimitiveWrappersModified(Class<?> fieldType, Field field, T object, Object value) throws IllegalArgumentException, IllegalAccessException {
        if (Double.class.isAssignableFrom(fieldType)) {
            field.set(object, value);
            return true;
        } else if (Long.class.isAssignableFrom(fieldType)) {
            field.set(object, ((Double)value).longValue());
            return true;
        } else if (Integer.class.isAssignableFrom(fieldType)) {
            field.set(object, ((Double)value).intValue());
            return true;
        } else if (Boolean.class.isAssignableFrom(fieldType)) {
            field.set(object, Boolean.valueOf(String.valueOf(value)));
            return true;
        } else {
            return false;
        }
    }

    public <T> List<T> myQueryByHaveSourceData(Query query,Class clazz,List<T> resData,Set<String> clause){
        this.throwExceptionIfMissingAnnotation(clazz);
        QueryResult queryResult = this.influxDB.query(query);
        String measurementName = InfluxDBHandleUtil.getMeasurementName(clazz);
        Map<Map<String,String>,T>  map = getResDataMapAndRestClause(clause,resData,clazz);
        return this.toPOJOByMyColumnByHaveSourceData(queryResult, clazz, measurementName, TimeUnit.MILLISECONDS,map,clause);
    }
    /**
     * 将符合clounm注解的数据赋值到字段中
     * 将符合myclounm注解的数据赋值到字段中
     * 不区分时间线
     * @param clazz
     * @param precision
     * @param <T>
     * @return
     */
    public <T> List<T> toPOJOByMyColumnByHaveSourceData(QueryResult queryResult, Class<T> clazz, String measurementName, TimeUnit precision
        ,Map<Map<String,String>,T> resData,Set<String> clause) throws InfluxDBMapperException {
        Objects.requireNonNull(measurementName, "measurementName");
        Objects.requireNonNull(queryResult, "queryResult");
        Objects.requireNonNull(clazz, "clazz");
        this.throwExceptionIfResultWithError(queryResult);
        List<T> result = new LinkedList<>();
        queryResult.getResults().stream().filter((internalResult) -> {
            return Objects.nonNull(internalResult) && Objects.nonNull(internalResult.getSeries());
        }).forEach((internalResult) -> {
            internalResult.getSeries().stream().filter((series) -> {
                return series.getName().equals(measurementName);
            }).forEachOrdered((series) -> {
                this.myParesByHaveSourceData(series, clazz, result, precision,resData,clause);
            });
        });
        return result;
    }
    /**
     * 压制原始数据到结果集（为配合结构化数据库准备）
     * @param series
     * @param clazz
     * @param result
     * @param precision
     * @param resData 由原始带有数据的对象集合和
     * @param clause 声明的比对字段
     * @param <T>
     * @return
     */
    <T> List<T> myParesByHaveSourceData(QueryResult.Series series, Class<T> clazz,List<T> result, TimeUnit precision,
                                        Map<Map<String,String>,T> resData,Set<String> clause) {
        int columnSize = series.getColumns().size();
        ConcurrentMap colNameAndFieldMap = InfluxDBHandleUtil.getColumn(clazz);
        ConcurrentMap myColumnAnnotation = InfluxDBHandleUtil.getMyColumnAnnotation(clazz);
        ConcurrentMap<String,String> clauseAndValue = new ConcurrentHashMap();
        try {
            T object = null;
            Iterator var8 = series.getValues().iterator();

            //记录并设定tag
            int flag = 0;
            T seriesObject = clazz.newInstance();
            while(var8.hasNext()) {
                List<Object> row = (List)var8.next();

                for(int i = 0; i < columnSize; ++i) {
                    Field correspondingField = (Field)colNameAndFieldMap.get(series.getColumns().get(i));

                    if (correspondingField != null) {
                        if (object == null) {
                            object = clazz.newInstance();
                        }

                        this.setFieldValue(object, correspondingField, row.get(i), precision);
                    }else {
                        Field myColumn = (Field)myColumnAnnotation.get(series.getColumns().get(i));
                        if (myColumn != null) {
                            if (object == null) {
                                object = clazz.newInstance();
                            }
                            this.setFieldValue(object, myColumn, row.get(i), precision);
                        }
                    }
                    //判断如果此字段是声明的比对字段，则压入map
                    if(clause.contains(series.getColumns().get(i))){
                        clauseAndValue.put(series.getColumns().get(i),row.get(i).toString());
                    }
                }

                if (series.getTags() != null && !series.getTags().isEmpty()) {
                    Iterator var14 = series.getTags().entrySet().iterator();

                    while(var14.hasNext()) {
                        Map.Entry<String, String> entry = (Map.Entry)var14.next();
                        Field correspondingField = (Field)colNameAndFieldMap.get(entry.getKey());
                        if (correspondingField != null) {
                            this.setFieldValue(object, correspondingField, entry.getValue(), precision);
                            if(flag==0){
                                this.setFieldValue(seriesObject, correspondingField, entry.getValue(), precision);
                            }
                        }
                        //判断如果此字段是声明的比对字段，则压入map
                        if(clause.contains(entry.getKey())){
                            clauseAndValue.put(entry.getKey(),entry.getValue());
                        }
                    }
                }

                if (object != null) {
                    pr(object,clauseAndValue,resData);
                    result.add(object);
                    object = null;
                }
                flag++;
            }
            return result;
        } catch (IllegalAccessException | InstantiationException var13) {
            throw new InfluxDBMapperException(var13);
        }
    }
    public <T> Map<T,List<T>> myQueryByHaveSourceDataGroupBySeries(Query query,Class clazz,List<T> resData,Set<String> clause){
        this.throwExceptionIfMissingAnnotation(clazz);
        QueryResult queryResult = this.influxDB.query(query);
        String measurementName = InfluxDBHandleUtil.getMeasurementName(clazz);
        Map<Map<String,String>,T>  map = getResDataMapAndRestClause(clause,resData,clazz);
        return this.toPOJOByMyColumnByHaveSourceDataGroupBySeries(queryResult, clazz, measurementName, TimeUnit.MILLISECONDS,map,clause);
    }
    /**
     * 将符合clounm注解的数据赋值到字段中
     * 将符合myclounm注解的数据赋值到字段中
     * 不区分时间线
     * @param clazz
     * @param precision
     * @param <T>
     * @return
     */
    public <T> Map<T,List<T>> toPOJOByMyColumnByHaveSourceDataGroupBySeries(QueryResult queryResult, Class<T> clazz, String measurementName, TimeUnit precision
        ,Map<Map<String,String>,T> resData,Set<String> clause) throws InfluxDBMapperException {
        Objects.requireNonNull(measurementName, "measurementName");
        Objects.requireNonNull(queryResult, "queryResult");
        Objects.requireNonNull(clazz, "clazz");
        this.throwExceptionIfResultWithError(queryResult);
        Map<T,List<T>> result = new ConcurrentHashMap<>();
        queryResult.getResults().stream().filter((internalResult) -> {
            return Objects.nonNull(internalResult) && Objects.nonNull(internalResult.getSeries());
        }).forEach((internalResult) -> {
            internalResult.getSeries().stream().filter((series) -> {
                return series.getName().equals(measurementName);
            }).forEachOrdered((series) -> {
                this.myParesByHaveSourceDataGroupBySeries(series, clazz, result, precision,resData,clause);
            });
        });
        return result;
    }
    /**
     * 压制原始数据到结果集（为配合结构化数据库准备）
     * @param series
     * @param clazz
     * @param result
     * @param precision
     * @param resData 由原始带有数据的对象集合和
     * @param clause 声明的比对字段
     * @param <T>
     * @return
     */
    <T> Map<T,List<T>> myParesByHaveSourceDataGroupBySeries(QueryResult.Series series, Class<T> clazz,Map<T,List<T>> result, TimeUnit precision,
                                        Map<Map<String,String>,T> resData,Set<String> clause) {
        int columnSize = series.getColumns().size();
        ConcurrentMap colNameAndFieldMap = InfluxDBHandleUtil.getColumn(clazz);
        ConcurrentMap myColumnAnnotation = InfluxDBHandleUtil.getMyColumnAnnotation(clazz);
        ConcurrentMap<String,String> clauseAndValue = new ConcurrentHashMap();
        List<T> list = new LinkedList<>();
        try {
            T object = null;
            Iterator var8 = series.getValues().iterator();

            //记录并设定tag
            int flag = 0;
            T seriesObject = clazz.newInstance();
            while(var8.hasNext()) {
                List<Object> row = (List)var8.next();

                for(int i = 0; i < columnSize; ++i) {
                    Field correspondingField = (Field)colNameAndFieldMap.get(series.getColumns().get(i));

                    if (correspondingField != null) {
                        if (object == null) {
                            object = clazz.newInstance();
                        }

                        this.setFieldValue(object, correspondingField, row.get(i), precision);
                    }else {
                        Field myColumn = (Field)myColumnAnnotation.get(series.getColumns().get(i));
                        if (myColumn != null) {
                            if (object == null) {
                                object = clazz.newInstance();
                            }
                            this.setFieldValue(object, myColumn, row.get(i), precision);
                        }
                    }
                    //判断如果此字段是声明的比对字段，则压入map
                    if(clause.contains(series.getColumns().get(i))){
                        clauseAndValue.put(series.getColumns().get(i),row.get(i).toString());
                    }
                }

                if (series.getTags() != null && !series.getTags().isEmpty()) {
                    Iterator var14 = series.getTags().entrySet().iterator();

                    while(var14.hasNext()) {
                        Map.Entry<String, String> entry = (Map.Entry)var14.next();
                        Field correspondingField = (Field)colNameAndFieldMap.get(entry.getKey());
                        if (correspondingField != null) {
                            this.setFieldValue(object, correspondingField, entry.getValue(), precision);
                            if(flag==0){
                                this.setFieldValue(seriesObject, correspondingField, entry.getValue(), precision);
                            }
                        }
                        //判断如果此字段是声明的比对字段，则压入map
                        if(clause.contains(entry.getKey())){
                            clauseAndValue.put(entry.getKey(),entry.getValue());
                        }
                    }
                }

                if (object != null) {
                    pr(object,clauseAndValue,resData);
                    list.add(object);
                    object = null;
                }
                flag++;
            }
            result.put(seriesObject,list);
            return result;
        } catch (IllegalAccessException | InstantiationException var13) {
            throw new InfluxDBMapperException(var13);
        }
    }
    public static String[] getNullPropertyNames (Object source,String ...ignore) {
        Map<String,Boolean> ignoreMap = new HashMap<>();
        for (String ign:ignore){
            ignoreMap.put(ign,true);
        }
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<String>();
        for(java.beans.PropertyDescriptor pd : pds) {
            if(ignoreMap.get(pd.getName())!=null){

            }else {
                Object srcValue = src.getPropertyValue(pd.getName());
                if (srcValue == null) emptyNames.add(pd.getName());
            }
        }
        String[] result = new String[emptyNames.size()];
        //date属性不复制
        emptyNames.add("date");
        return emptyNames.toArray(result);
    }
    private <T> void pr(T object,Map<String,String> clauseAndValue,Map<Map<String,String>,T> resData) {
        if(clauseAndValue!=null&&resData!=null&&!clauseAndValue.isEmpty()&&!resData.isEmpty()){
            if(resData.get(clauseAndValue)!=null){
                BeanUtils.copyProperties(resData.get(clauseAndValue),object,getNullPropertyNames(resData.get(clauseAndValue),"date"));
            }
        }
    }
    private <T> Map<Map<String,String>,T> getResDataMapAndRestClause(Set<String> clause,List<T> resData,Class clazz) {
        if(resData==null||resData.isEmpty()){
            return null;
        }
        Map<Map<String,String>,T> resDataMap = new HashMap<>();
        Map<String,List<Field>> allFields = InfluxDBHandleUtil.getAllColumnList(clazz);

        Set<String> clauseNew = new HashSet<>();
        Iterator<T> iterator = resData.iterator();
        while (iterator.hasNext()){
            Map<String,String> map = new HashMap<>();
            T r = iterator.next();
            for(String cla:clause){
                List<Field> fieldList = null;
                Field field = null;
//                try{
//                    field = clazz.getDeclaredField(cla);
//                } catch (NoSuchFieldException e) {
//                    //field不存在
//                }
                fieldList = allFields.get(cla);
                map.put(cla,null);
                if(fieldList.size()==1){
                    clauseNew.add(cla);
                    field = fieldList.get(0);
                    if(field!=null){

                        if (!field.isAccessible()) {
                            field.setAccessible(true);
                        }
                        //字段值
                        Object value = null;
                        try {
                            value = field.get(r);
                        } catch (IllegalAccessException e) {

                        }
                        if(value!=null){
                            map.put(cla,String.valueOf(value));
                        }else {
                            map.put(cla,null);
                        }
                    }
                }else if(fieldList.size()>1){
                    clauseNew.add(cla);
                    for(Field fieldin:fieldList){
                        if (!fieldin.isAccessible()) {
                            fieldin.setAccessible(true);
                        }
                        //字段值
                        Object value = null;
                        try {
                            value = fieldin.get(r);
                        } catch (IllegalAccessException e) {

                        }
                        if(value!=null){
                            map.put(cla,String.valueOf(value));
                            break;
                        }
                    }
                }

            }
            resDataMap.put(map,r);
        }
        clause.clear();
        clause.addAll(clauseNew);
        return resDataMap;
    }

    public <T> void save2PublicDatabase(final T model) {
        throwExceptionIfMissingAnnotation(model.getClass());

        ConcurrentMap<String, Field> colNameAndFieldMap = InfluxDBHandleUtil.getColumn(model.getClass());

        try {
            Class<?> modelType = model.getClass();
            String measurement = InfluxDBHandleUtil.getMeasurementName(modelType);
            String database = publicDatabase;
            String retentionPolicy = InfluxDBHandleUtil.getRetentionPolicy(modelType);
            TimeUnit timeUnit = InfluxDBHandleUtil.getTimeUnit(modelType);
            long time = timeUnit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
            Point.Builder pointBuilder = Point.measurement(measurement).time(time, timeUnit);

            for (String key : colNameAndFieldMap.keySet()) {
                Field field = colNameAndFieldMap.get(key);
                Column column = field.getAnnotation(Column.class);
                String columnName = column.name();
                Class<?> fieldType = field.getType();

                if (!field.isAccessible()) {
                    field.setAccessible(true);
                }

                Object value = field.get(model);

                if (column.tag()) {
                    /** Tags are strings either way. */
                    if (value == null) {
                        pointBuilder.tag(columnName, "");
                    } else {
                        pointBuilder.tag(columnName, value.toString());
                    }

                } else if ("time".equals(columnName)) {
                    if (value != null) {
                        InfluxDBHandleUtil.setTime(pointBuilder, fieldType, timeUnit, value);
                    }
                } else {
                    InfluxDBHandleUtil.setField(pointBuilder, fieldType, columnName, value);
                }
            }

            Point point = pointBuilder.build();

            if ("[unassigned]".equals(database)) {
                influxDB.write(point);
            } else {
                influxDB.write(database, retentionPolicy, point);
            }

        } catch (IllegalAccessException e) {
            throw new InfluxDBMapperException(e);
        }
    }
}
